﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Resources;
using System.Security.AccessControl;
using System.Data;
using EncryptProject;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Runtime.InteropServices;
using System.Configuration;
using System.IO;
using System.Collections;
using FileLib;
using RegistryLib;
using DataLib;
using SoftKeyLib;
using DBLib;
using CommonBase;
using System.Net.NetworkInformation;
using System.Net;

namespace CommonClass
{
    /// <summary>
    /// 公共静态方法与常量
    /// </summary>
    public static class Utilities
    {
        #region 常量

        /// <summary>
        /// 错误信息显示格式
        /// </summary>
        public const string ERROR_INFORMATION_STYLE = "代码: {0}\n描述: {1}";

        #region INI

        /// <summary>
        /// ini 文件[段落]
        /// </summary>
        public const string INI_SECTIONNAME = "软件注册";

        /// <summary>
        /// ini 文件 key
        /// </summary>
        public const string INI_KEYNAME = "机器码";

        #endregion

        /// <summary>
        /// 试用版本最大试用次数
        /// </summary>
        private const int TRIAL_TIMES = 50;

        /// <summary>
        /// 正则表达式之 IPv4
        /// </summary>
        private const string REGULAR_IPV4 = @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$";

        #endregion

        #region 属性

        /// <summary>
        /// 数据库名称
        /// </summary>
        public static string DatabaseName { get; set; }

        /// <summary>
        /// 主项目 GUID
        /// </summary>
        public static string ProjectGUID { get; set; }

        /// <summary>
        /// 生成机器码，用于加解密的密钥
        /// </summary>
        public static string MachineCode { get; set; }

        /// <summary>
        /// DebugModel
        /// </summary>
        public static bool DebugModel { get; set; }

        #endregion

        #region 方法

        /// <summary>
        /// 获取本项目 GUID
        /// </summary>
        /// <returns>(string)GUID</returns>
        public static string GetProjectGUID()
        {
            try
            {
                Attribute guidAttr = Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
                    typeof(GuidAttribute));

                return ((GuidAttribute)guidAttr).Value;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 根据查询条件获得对应表信息
        /// <para>初始化数据库，判定是否可以正常连接到数据库</para>
        /// </summary>
        /// <param name="cmdText">查询的文本</param>
        /// <param name="tbName">数据表名称</param>
        /// <returns>返回数据库中保存的信息</returns>
        public static DataTable GetDataTable(string cmdText, string tbName = null)
        {
            try
            {
                DataOperation dataOperation = new DataOperation();
                DataSet dataset = dataOperation.GetDataSet(cmdText, tbName,
                    "db_VWMSConnectionString", string.Format("{0}.exe", Application.ProductName));
                if (dataset == null ||
                    (dataset != null && dataset.Tables.Count <= 0))
                    return null;
                else
                    return dataset.Tables[0];
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return null;
        }

        /// <summary>
        /// 备份数据库
        /// </summary>
        /// <param name="backupPathInAppSettings">App.config 中的数据库备份路径</param>
        /// <param name="databaseName">数据库名称</param>
        public static void BackupDatabase(string backupPathInAppSettings,
            string databaseName)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(backupPathInAppSettings) ||
                    string.IsNullOrWhiteSpace(databaseName))
                    return;

                if (ConfigurationManager.AppSettings.AllKeys.Contains(backupPathInAppSettings)) // 备份数据库到指定位置（App.config）
                {
                    string sourceFileName = string.Format(@"{0}\DataBase\{1}.mdb",
                        Environment.CurrentDirectory, databaseName);
                    string destFileName = System.IO.Path.Combine(ConfigurationManager.AppSettings[backupPathInAppSettings],
                        string.Format("{0}.mdb", databaseName));

                    FileOperation.CreatDirectory(ConfigurationManager.AppSettings[backupPathInAppSettings]); // 创建目录
                    FileOperation.CopyFile(sourceFileName, destFileName);
                }
                else
                {
#if DEBUG
                    Debug.WriteLine("App.config 里不包含自动备份路径！");
#endif
                }
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 修改数据库文件权限，增加 Users 用户对 mdb 文件的修改权限
        /// </summary>
        /// <param name="databaseName">数据库名称</param>
        public static void ChangeDBFileAccessControl(string databaseName)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(databaseName))
                    return;

                Utilities.ChangeFileAccessControl(string.Format(@"{0}\{1}\{2}.mdb", Environment.CurrentDirectory,
                    "DataBase", databaseName), "Users", FileSystemRights.Modify, AccessControlType.Allow);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 修改文件权限，增加 Users 用户对文件的修改权限
        /// </summary>
        /// <param name="fileName">文件路径</param>
        public static void ChangeFileAccessControl(string fileName)
        {
            try
            {
                Utilities.ChangeFileAccessControl(fileName, "Users",
                    FileSystemRights.Modify, AccessControlType.Allow);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 更改文件权限
        /// </summary>
        /// <param name="fileName">文件路径</param>
        /// <param name="account">用户账户名称</param>
        /// <param name="rights">操作访问规则</param>
        /// <param name="controlType">允许 | 拒绝该操作</param>
        public static void ChangeFileAccessControl(string fileName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            if (string.IsNullOrWhiteSpace(fileName) ||
                string.IsNullOrWhiteSpace(account))
                return;

            try
            {
                FileAccessControl.AddFileSecurity(fileName, account, rights, controlType);
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                MessageBox.Show(ex.Message, ConstantString.MSG_COMPANY, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        /// <summary>
        /// 绘制面板边框,http://blog.163.com/y_p_xu/blog/static/1708571022011101265538446/
        /// </summary>
        /// <param name="pnl">要绘制边框的Panel</param>
        /// <param name="col">边框颜色</param>
        /// <param name="bWidth">边框宽度</param>
        /// <param name="bStyle">边框样式</param>
        public static void PaintPanelBorder(Panel pnl, Color col, int bWidth,
            ButtonBorderStyle bStyle)
        {
            try
            {
                PaintEventArgs e = new PaintEventArgs(pnl.CreateGraphics(), pnl.ClientRectangle);
                ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle,
                    col, bWidth, bStyle,
                    col, bWidth, bStyle,
                    col, bWidth, bStyle,
                    col, bWidth, bStyle);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 检查加密锁判断是否可绑定锁（新锁 | 补锁）
        /// </summary>
        /// <param name="regCode">用户注册码</param>
        /// <param name="keyOperation">加密锁操作类</param>
        /// <param name="wndHandle">窗口句柄</param>
        /// <returns>是否绑定成功</returns>
        public static bool CheckSoftKey4BindingKey(IntPtr wndHandle, string regCode,
            SoftKeyOperation keyOperation = null)
        {
            try
            {
                if (wndHandle == null || string.IsNullOrWhiteSpace(regCode))
                    throw new ArgumentNullException("参数必须赋初值！");

                if (keyOperation == null)
                    keyOperation = new SoftKeyOperation();

                string outReadString = string.Empty; // 记录加密锁里的加密字符串的值
                SoftKeyErrorEnum errorCodeEnum = SoftKeyErrorEnum.CannotFindSoftKey; // 加密锁错误代码，默认：无锁

                // 先判断加密锁
                if (keyOperation.EasyFindSoftKey(wndHandle)) // 简单寻找加密锁，判断系统中是否存在着加密锁，不需要是指定的加密锁
                {
                    if (keyOperation.FindSoftKey()) // 多方式寻找加密锁，锁中密码的验证
                    {
                        if (keyOperation.GetStringFromSoftKey(ref outReadString)) // 从加密锁中读信息（这里读出的字符 <= 32 个），判断锁是否已被绑定
                        {
                            if (!string.IsNullOrWhiteSpace(outReadString) &&
                                outReadString.Contains(SoftKeyOperation.KEY_EPROM)) // 新锁
                            {
#if DEBUG
                                Debug.WriteLine("存入的值为储存器默认值。");
#endif
                                errorCodeEnum = SoftKeyErrorEnum.SoftKeyIsOK; // 还需要进行进一步判断加密锁：表示加密锁密码正确且写入的数据为储存器默认值，下一步写入数据到锁中
                            }
                            else // 旧锁
                            {
#if DEBUG
                                Debug.WriteLine("锁中存在其它数据或为空，是旧锁或出厂锁！不能绑定。请重置加密锁！");
#endif
                                errorCodeEnum = SoftKeyErrorEnum.CannotBindingOldKey;
                            }
                        }
                        else // 读取加密锁中的加密字符串失败(部分新锁 | 存入的值有问题 | 密码错误)
                        {
#if DEBUG
                            Debug.WriteLine("锁异常：新锁 | 存入的值有问题 | 密码错误。请重置加密锁！");
#endif
                            errorCodeEnum = SoftKeyErrorEnum.OtherException;
                        }
                    }
                    else
                    {
#if DEBUG
                        Debug.WriteLine("写密码、读密码、算法密码不正确！请重置加密锁！");
#endif
                        errorCodeEnum = SoftKeyErrorEnum.WrongPasswordInSoftKey;
                    }
                }
                else
                {
#if DEBUG
                    Debug.WriteLine("未找到加密锁！");
#endif
                    errorCodeEnum = SoftKeyErrorEnum.CannotFindSoftKey;
                }

                // 只有加密锁正常就绪时才有意义
                if (errorCodeEnum != SoftKeyErrorEnum.SoftKeyIsOK) // 不为正常就绪的情况时
                {
                    MessageBox.Show(string.Format(Utilities.ERROR_INFORMATION_STYLE,
                        (int)errorCodeEnum, Utilities.GetEnumDisplayDescription(errorCodeEnum)),
                        ConstantString.MSG_COMPANY);

                    return false;
                }

                // 再写入 MD5 值
                string softKeyID = keyOperation.GetChipID(); // 得到新加密锁的唯一 ID
                if (!string.IsNullOrWhiteSpace(regCode) &&
                    !string.IsNullOrWhiteSpace(softKeyID))
                {
                    if (keyOperation.PutString2SoftKey(EncryptAlgorithmHelper.MD5Hash(string.Format(SoftKeyOperation.MD5_FORMAT_STYLE4USER,
                        regCode, softKeyID)))) // 将数据写入加密锁中
                    {
#if DEBUG
                        Debug.WriteLine("绑定成功！");
#endif
                        return true;
                    }
                    else
                    {
#if DEBUG
                        Debug.WriteLine("数据写入到加密锁中异常！");
#endif
                        errorCodeEnum = SoftKeyErrorEnum.OtherException;
                    }
                }
                else
                {
#if DEBUG
                    Debug.WriteLine("获得加密锁 ID 错误！");
#endif
                    errorCodeEnum = SoftKeyErrorEnum.OtherException;
                }

                if (errorCodeEnum != SoftKeyErrorEnum.SoftKeyIsOK) // 不为正常就绪的情况时
                {
                    MessageBox.Show(string.Format(Utilities.ERROR_INFORMATION_STYLE,
                        (int)errorCodeEnum, Utilities.GetEnumDisplayDescription(errorCodeEnum)),
                        ConstantString.MSG_COMPANY);
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return false;
        }

        /// <summary>
        /// 检查加密锁判断是正式版用户还是试用版用户
        /// </summary>
        /// <param name="dsSystem">SystemInformation 表数据集</param>
        /// <param name="keyOperation">加密锁操作类</param>
        /// <param name="wndHandle">窗口句柄</param>
        /// <param name="drSystem">SystemInformation 表的信息【只含唯一一条记录】</param>
        /// <param name="title">试用版 | 正式版</param>
        /// <returns>true: 正式版用户；false: 试用版用户</returns>
        public static bool CheckSoftKey4User(DataSet dsSystem, IntPtr wndHandle,
            out DataRow drSystem, out string title, SoftKeyOperation keyOperation = null)
        {
            title = "【试用版】"; // 标题
            drSystem = null;

            try
            {
                if (dsSystem == null || wndHandle == null)
                    throw new ArgumentNullException("参数必须赋初值！");

                if (keyOperation == null)
                    keyOperation = new SoftKeyOperation();

                string outReadString = string.Empty; // 记录加密锁里的加密字符串的值
                SoftKeyErrorEnum errorCodeEnum = SoftKeyErrorEnum.CannotFindSoftKey; // 加密锁错误代码，默认：无锁

                if (dsSystem.Tables.Count > 0)
                {
                    // 先判断加密锁
                    if (keyOperation.EasyFindSoftKey(wndHandle)) // 简单寻找加密锁，判断系统中是否存在着加密锁，不需要是指定的加密锁
                    {
                        if (keyOperation.FindSoftKey()) // 多方式寻找加密锁，锁中密码的验证
                        {
                            if (keyOperation.GetStringFromSoftKey(ref outReadString)) // 从加密锁中读信息（这里读出的字符 <= 32 个），判断锁是否已被绑定
                            {
                                if (!string.IsNullOrWhiteSpace(outReadString) &&
                                    outReadString.Length == SoftKeyOperation.KEYSTRING_LENGTH) // 旧锁（32 位字符串）
                                {
                                    errorCodeEnum = SoftKeyErrorEnum.SoftKeyIsOK; // 还需要进行进一步判断加密锁：表示加密锁密码正确且有数据写入到锁中，但还需进一步验证写入锁中数据的正确性
                                }
                                else if (!string.IsNullOrWhiteSpace(outReadString) &&
                                    outReadString.Contains(SoftKeyOperation.KEY_EPROM)) // 新锁
                                {
#if DEBUG
                                    Debug.WriteLine("储存器默认值");
#endif
                                    errorCodeEnum = SoftKeyErrorEnum.BindingNewSoftKey;
                                }
                                else // 不是 MD5 值
                                {
#if DEBUG
                                    Debug.WriteLine("存入的值为 null 或空格串，或并非 MD5 值！");
#endif
                                    errorCodeEnum = SoftKeyErrorEnum.CannotMatchSoftKey;
                                }
                            }
                            else // 读取加密锁中的加密字符串失败(部分新锁 | 存入的值有问题 | 密码错误)
                            {
#if DEBUG
                                Debug.WriteLine("没有获取到加密锁里的 MD5 值！锁可能异常。");
#endif
                                errorCodeEnum = SoftKeyErrorEnum.BindingSoftKeyFirst;
                            }
                        }
                        else
                        {
#if DEBUG
                            Debug.WriteLine("写密码、读密码、算法密码不正确！");
#endif
                            errorCodeEnum = SoftKeyErrorEnum.WrongPasswordInSoftKey;
                        }
                    }
                    else
                    {
#if DEBUG
                        Debug.WriteLine("未找到加密锁！");
#endif
                        errorCodeEnum = SoftKeyErrorEnum.CannotFindSoftKey;
                    }

                    // 再判断数据库中的数据
                    if (dsSystem.Tables[0].Rows.Count > 0) // 数据库中存在系统数据
                        drSystem = dsSystem.Tables[0].Rows[0]; // 返回第一条记录，因表里只有一条数据
                    else // 数据库中不存在数据
                        drSystem = dsSystem.Tables[0].NewRow(); // 添加一个新数据行

                    if (drSystem != null &&
                        errorCodeEnum == SoftKeyErrorEnum.SoftKeyIsOK) // 锁正常就绪时，判断才有意义
                    {
                        if (drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID] != null) // 判数据库中是否存在 SoftKeyID 字段
                        {
                            #region 赋初值
                            if (drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] == null ||
                                (drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] != null &&
                                string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM].ToString()))) // 机器码
                            {
                                #region 生成唯一机器码
                                GenerateMachineCode();
                                #endregion

                                drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] = Utilities.MachineCode; // 生成唯一自定义机器码
                            }

                            if (drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES] == null ||
                                (drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES] != null &&
                                string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES].ToString()))) // 试用次数
                            {
                                drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES] =
                                    EncryptAlgorithmHelper.Encrypt2("0", Utilities.MachineCode); // 默认未试用过
                            }
                            #endregion

                            string softKeyID = keyOperation.GetChipID(); // 得到新加密锁的唯一 ID
                            if (drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID].ToString().Equals(
                                softKeyID)) // 判断加密锁芯片唯一 ID 是否与数据库所存值保存一致，即：该锁是否绑定该主机
                            {
#if DEBUG
                                Debug.WriteLine("旧锁？");
#endif
                                DateTime outTokenTime;
                                if (drSystem[RegistryOperation.SUBKEYNAME_TOKEN] != null &&
                                    DateTime.TryParse(
                                        EncryptAlgorithmHelper.Decrypt(drSystem[RegistryOperation.SUBKEYNAME_TOKEN].ToString()),
                                        out outTokenTime)) // 解密 Token 为时间值
                                {
                                    //////////////////////////////////////////////////////////////////////////
                                    // 数据库的数据完整且加密锁数据一切正常时，计算 MD5 值是否与加密锁保持一致，判断旧锁情况
                                    //////////////////////////////////////////////////////////////////////////
                                    if (drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID] != null &&
                                        !string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID].ToString()) &&
                                        drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] != null &&
                                        !string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM].ToString()))
                                    {
                                        string companyMD5 = EncryptAlgorithmHelper.MD5Hash(string.Format(SoftKeyOperation.MD5_FORMAT_STYLE4COMPANY,
                                            drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM].ToString(),
                                            outTokenTime, Utilities.ProjectGUID)); // MD5（对公司）
                                        string userMD5 = EncryptAlgorithmHelper.MD5Hash(string.Format(SoftKeyOperation.MD5_FORMAT_STYLE4USER, companyMD5,
                                            drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID].ToString())); // MD5（对用户）

                                        if (!string.IsNullOrWhiteSpace(outReadString) &&
                                            outReadString.Length == SoftKeyOperation.KEYSTRING_LENGTH &&
                                            userMD5.Equals(outReadString)) // 判断 MD5 值
                                        {
                                            title = "【正式版】";
                                            return true; // 正式版用户（旧锁匹配成功）
                                        }
                                        else
                                        {
#if DEBUG
                                            Debug.WriteLine("数据库异常或加密锁不匹配！");
#endif
                                            errorCodeEnum = SoftKeyErrorEnum.BuyNewSoftKey4OldKey2;
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        Debug.WriteLine("数据库信息不全：SoftKeyID、MachineNum、Token");
#endif
                                        throw new DataException("数据库信息不全：SoftKeyID、MachineNum、Token");
                                    }
                                }
                                else
                                {
#if DEBUG
                                    Debug.WriteLine("数据库异常！");
#endif
                                    errorCodeEnum = SoftKeyErrorEnum.BuyNewSoftKey4OldKey1;

                                }
                            }
                            else
                            {
#if DEBUG
                                Debug.WriteLine("新锁/补锁？");
#endif
                                DateTime outMendTime;
                                if (drSystem[RegistryOperation.SUBKEYNAME_MENDTIME] != null &&
                                    DateTime.TryParse(drSystem[RegistryOperation.SUBKEYNAME_MENDTIME].ToString(),
                                        out outMendTime)) // 判断 MendTime 为时间值
                                {
                                    //////////////////////////////////////////////////////////////////////////
                                    // 数据库的数据完整且加密锁数据一切正常时，计算 MD5 值是否与加密锁保持一致，可判断新锁/补锁情况，即：补锁有效，丢失锁无效！
                                    //////////////////////////////////////////////////////////////////////////
                                    if (drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] != null &&
                                        !string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM].ToString()))
                                    {
                                        string companyMD5 = EncryptAlgorithmHelper.MD5Hash(string.Format(SoftKeyOperation.MD5_FORMAT_STYLE4COMPANY,
                                            drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM].ToString(),
                                            outMendTime, Utilities.ProjectGUID)); // MD5（对公司）
                                        string userMD5 = EncryptAlgorithmHelper.MD5Hash(string.Format(SoftKeyOperation.MD5_FORMAT_STYLE4USER, companyMD5,
                                            softKeyID)); // MD5（对用户）

                                        if (!string.IsNullOrWhiteSpace(outReadString) &&
                                            outReadString.Length == SoftKeyOperation.KEYSTRING_LENGTH &&
                                            userMD5.Equals(outReadString)) // 判断 MD5 值
                                        {
                                            title = "【正式版】";

                                            drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID] = softKeyID; // 得到新加密锁的唯一 ID
                                            drSystem[RegistryOperation.SUBKEYNAME_TOKEN] = EncryptAlgorithmHelper.Encrypt(drSystem[RegistryOperation.SUBKEYNAME_MENDTIME].ToString()); // MendTime 加密后填入到 Token 字段
                                            drSystem[RegistryOperation.SUBKEYNAME_MENDTIME] = string.Empty; // MendTime 为空

                                            return true; // 正式版用户（新锁/补锁成功）
                                        }
                                        else
                                        {
#if DEBUG
                                            Debug.WriteLine("数据库异常或加密锁不匹配！");
#endif
                                            errorCodeEnum = SoftKeyErrorEnum.BuyNewSoftKey4NewKey2;
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        Debug.WriteLine("数据库信息不全：SoftKeyID、MachineNum、MendTime");
#endif
                                        throw new DataException("数据库信息不全：SoftKeyID、MachineNum、MendTime");
                                    }
                                }
                                else
                                {
#if DEBUG
                                    Debug.WriteLine("数据库异常或加密锁不匹配(null)！");
#endif
                                    errorCodeEnum = SoftKeyErrorEnum.BuyNewSoftKey4NewKey1;

                                }
                            }
                        }
                        else
                        {
#if DEBUG
                            throw new DataException("数据库异常！");
#endif
                        }
                    }
                    else
                    {
#if DEBUG
                        Debug.WriteLine("其它加密锁错误！");
#endif
                    }
                }
                else
                {
#if DEBUG
                    throw new DataException("数据库异常！");
#endif
                }

                if (errorCodeEnum != SoftKeyErrorEnum.SoftKeyIsOK &&
                    errorCodeEnum != SoftKeyErrorEnum.CannotFindSoftKey) // 非正常就绪和未找到锁的情况时
                {
                    MessageBox.Show(string.Format(Utilities.ERROR_INFORMATION_STYLE,
                        (int)errorCodeEnum, Utilities.GetEnumDisplayDescription(errorCodeEnum)),
                        ConstantString.MSG_COMPANY);
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return false; // 试用版用户
        }

        /// <summary>
        /// 读写机器码【注册表与 ini 文件】，并判断试用次数，正式版用户继续使用
        /// </summary>
        /// <param name="isRegUser">true: 正式版用户；false: 试用版用户</param>
        /// <param name="drSystem">SystemInformation 表的信息【只含唯一一条记录】</param>
        /// <param name="changeControlButtonDisenableStateWhenExceptionAction">系统异常时处理情况</param>
        /// <param name="iniFileName">ini 文件名</param>
        /// <returns>试用完毕与否</returns>
        public static bool CheckTrialTimes(bool isRegUser, DataRow drSystem,
            string iniFileName,
            Action<string> changeControlButtonDisenableStateWhenExceptionAction = null)
        {
            if (string.IsNullOrEmpty(iniFileName))
                return false;

            // 1. 先初始化注册表与 ini 文件
            // 注册表 初始化
            RegistryOperation regOperation = new RegistryOperation();
            regOperation.CreateSubKey(); // 创建子项，若存在该项时无任何操作

            // ini 文件 初始化
            INIOperation iniOperation = new INIOperation();
            string iniPath = string.Format(@"{0}\{1}\{2}.ini", Application.StartupPath,
                "DataBase", iniFileName);
            int outValueLength; // ini 键值字符串长度

            // 2. 将 ini 文件中的机器码值与注册表中的机器码值同时进行比对
            // 这里可以简单验证用户复制本机程序到其它主机的情况
            string registryRegValue = string.Empty;
            object regValue = regOperation.GetSubKeyValue(); // 读注册表中的机器码
            if (regValue != null)
                registryRegValue = regValue.ToString();
            string iniRegValue = iniOperation.ReadValue(INI_SECTIONNAME, INI_KEYNAME,
                iniPath, out outValueLength); // 读 ini 文件中的机器码

            // 若不相同，或者都不存在时，重新写入机器码
            if (string.IsNullOrWhiteSpace(registryRegValue) ||
                string.IsNullOrWhiteSpace(iniRegValue) ||
                !registryRegValue.Equals(iniRegValue))
            {
                #region 生成唯一机器码
                GenerateMachineCode();
                #endregion

                registryRegValue = iniRegValue = Utilities.MachineCode;
                // 写机器码到注册表
                regOperation.SetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_MACHINENUM, registryRegValue);
                // 写机器码到 ini 文件
                iniOperation.WriteValue(INI_SECTIONNAME, INI_KEYNAME, iniRegValue, iniPath);
            }
            else // 存在相同的机器码时
            {
                Utilities.MachineCode = registryRegValue;
            }

            if (drSystem != null)
            {
                drSystem[RegistryOperation.SUBKEYNAME_MACHINENUM] = Utilities.MachineCode;
            }


            if (!isRegUser) // 只针对试用版用户
            {
                // 3. 再判断试用次数
                int outUseTimes = 0; // 记录已经试用次数、记录注册表中的试用次数
                object useTimes = regOperation.GetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_TRIALTIMES); // 从注册表中获取次数
                if (useTimes != null)
                {
                    try
                    {
                        outUseTimes = int.Parse(EncryptAlgorithmHelper.Decrypt2(useTimes.ToString(), Utilities.MachineCode));
                    }
                    catch (System.Exception ex)
                    {
#if DEBUG
                        Debug.WriteLine(ex.Message);
#endif
                        outUseTimes = int.MaxValue;
                    }
                }

                // 判断注册表中的试用次数是否与数据库中的试用次数匹配
                int outTrialTimes = 0; // 数据库中的试用次数
                if (outUseTimes != int.MaxValue &&
                    drSystem != null && drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES] != null &&
                    !string.IsNullOrWhiteSpace(drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES].ToString()))
                {
                    try
                    {
                        outTrialTimes = int.Parse(EncryptAlgorithmHelper.Decrypt2(drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES].ToString(), Utilities.MachineCode));
                        if (outUseTimes != outTrialTimes)
                            outUseTimes = Math.Max(outUseTimes, outTrialTimes); // 取最大值
                    }
                    catch (System.Exception ex)
                    {
#if DEBUG
                        Debug.WriteLine(ex.Message);
#endif
                        outUseTimes = outTrialTimes = int.MaxValue;
                    }
                }

                if (outUseTimes++ >= TRIAL_TIMES) // 达到试用次数
                {
                    if (changeControlButtonDisenableStateWhenExceptionAction != null)
                    {
                        changeControlButtonDisenableStateWhenExceptionAction("试用结束！请购买正版软件，谢谢。");
                    }

                    return true;
                }
                else // 可继续试用
                {
                    regOperation.SetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_TRIALTIMES,
                        outUseTimes < 0 ? EncryptAlgorithmHelper.Encrypt2("0", Utilities.MachineCode) :
                        EncryptAlgorithmHelper.Encrypt2(outUseTimes.ToString(), Utilities.MachineCode)); // 写入正确的试用次数到注册表
                    if (drSystem != null)
                    {
                        drSystem[RegistryOperation.SUBKEYNAME_TRIALTIMES] =
                            EncryptAlgorithmHelper.Encrypt2(outUseTimes.ToString(), Utilities.MachineCode);
                    }

                    MessageBox.Show(
                        string.Format("温馨提示：\n该软件可以免费试用 {0} 次\n您已经试用 {1} 次", TRIAL_TIMES, outUseTimes),
                        ConstantString.MSG_COMPANY);
                }
            }

            if (drSystem != null) // 只是记录到注册表中，没任何作用
            {
                regOperation.SetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_TOKEN,
                    drSystem[RegistryOperation.SUBKEYNAME_TOKEN] != null ? drSystem[RegistryOperation.SUBKEYNAME_TOKEN].ToString() : string.Empty); // 写入正确的 Token 到注册表
                regOperation.SetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_MENDTIME,
                    drSystem[RegistryOperation.SUBKEYNAME_MENDTIME] != null ? drSystem[RegistryOperation.SUBKEYNAME_MENDTIME].ToString() : string.Empty); // 写入正确的补锁时间到注册表
                regOperation.SetSubKeyValue(null, null, RegistryOperation.SUBKEYNAME_SOFTKEYID,
                    drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID] != null ? drSystem[RegistryOperation.SUBKEYNAME_SOFTKEYID].ToString() : string.Empty); // 写入正确的加密锁编号到注册表
            }

            return false;
        }

        /// <summary>
        /// 生成机器码
        /// </summary>
        public static void GenerateMachineCode()
        {
            SoftReg reg = new SoftReg();
            Utilities.MachineCode = reg.GetMNum(); // 生成唯一自定义机器码
        }

        /// <summary>
        /// 深拷贝，将 source 拷贝至 destination
        /// </summary>
        /// <param name="source">源</param>
        /// <param name="destination">目标</param>
        public static void CopyObject(object source, object destination)
        {
            try
            {
                Memento memento = new Memento();
                memento.StoreObjectProps(source);
                memento.RetrieveObjectProps(destination);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 判断 IP 是否合法
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool ValidIP(string ip)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(ip) || ip.Length < 7 || ip.Length > 15)
                    return false;
                else
                {
                    Regex regular = new Regex(REGULAR_IPV4, RegexOptions.IgnoreCase);
                    return regular.IsMatch(ip);
                }
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 判断端口号是否合法
        /// </summary>
        /// <param name="port"></param>
        /// <returns></returns>
        public static bool ValidIPPort(string port)
        {
            try
            {
                bool isPort = false;
                int outPortNum;
                isPort = int.TryParse(port, out outPortNum);

                if (isPort && outPortNum >= 0 && outPortNum <= 65535)
                    isPort = true;
                else
                    isPort = false;

                return isPort;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// Ping 命令
        /// </summary>
        /// <param name="ip">主机 / IP</param>
        /// <returns></returns>
        public static PingReply PingCommand(string ip)
        {
            Ping ping = new Ping();

            try
            {
                return ping.Send(ip);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return null;
            }
            finally
            {
                ping.Dispose();
            }
        }

        /// <summary>
        /// Ping 命令
        /// </summary>
        /// <param name="ip">IP</param>
        /// <returns></returns>
        public static PingReply PingCommand(IPAddress ip)
        {
            Ping ping = new Ping();

            try
            {
                return ping.Send(ip);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return null;
            }
            finally
            {
                ping.Dispose();
            }
        }

        /// <summary> 
        /// 将文件大小(字节)转换为最适合的显示方式 
        /// </summary> 
        /// <param name="size">bytes 字节</param> 
        /// <returns></returns> 
        public static string ConvertFileSize(long size)
        {
            try
            {
                string result = "0KB";
                int filelength = size.ToString().Length;

                if (filelength < 4)
                    result = size + "byte";
                else if (filelength < 7)
                    result = Math.Round(Convert.ToDouble(size / 1024d), 2) + "KB";
                else if (filelength < 10)
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024), 2) + "MB";
                else if (filelength < 13)
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024 / 1024), 2) + "GB";
                else
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024 / 1024 / 1024), 2) + "TB";

                return result;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 修改“全选”CheckBox 状态
        /// <para>三态显示，注：须包含“IsSelected”属性</para>
        /// </summary>
        /// <param name="collections"></param>
        /// <returns></returns>
        public static bool? SetSelectAllCheckBoxState(IEnumerable collections)
        {
            try
            {
                bool hasTrue = false, hasFalse = false; // 是否包含“真”、“假”值

                foreach (var item in collections)
                {
                    if (item.GetType().GetProperty("IsSelected") == null)
                        continue;

                    if (item.GetType().GetProperty("IsSelected").GetValue(item, null) == null)
                        break;

                    if ((bool)item.GetType().GetProperty("IsSelected").GetValue(item, null)) // True
                        hasTrue = true;
                    else if (!(bool)item.GetType().GetProperty("IsSelected").GetValue(item, null)) // False
                        hasFalse = true;
                }

                if (hasTrue && !hasFalse)
                    return true; // 只含“True”
                else if (!hasTrue && hasFalse)
                    return false; // 只含“False”
                else if (hasTrue && hasFalse)
                    return null; // 两者都含
                else
                    return null; // 默认时
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 根据项目类别获取更新版本路径
        /// </summary>
        /// <param name="projectType">项目类别 ProjectTypeEnum</param>
        /// <returns></returns>
        public static string GetUpgradePath(string projectType)
        {
            try
            {
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, projectType,
                    "Upgrade"); // 由于是 IIS，不要使用 Application.StartupPath 和 Environment.CurrentDirectory
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 根据更新版本路径获取最新版本号
        /// </summary>
        /// <param name="upgradePath">更新版本路径</param>
        /// <returns></returns>
        public static string GetLatestVersion(string upgradePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(upgradePath))
                    return string.Empty;

                string[] updateFileList = FileOperation.GetDirectories(upgradePath); // 获得所有更新文件名称列表
                if (updateFileList != null && updateFileList.Length > 0)
                {
                    string latestFileName = string.Empty; // 记录最新版本号文件名称
                    string[] latestVersion = null; // 记录最新版本号
                    string[] fileVersion = null; // 记录单个文件版本号
                    int outVersion;

                    foreach (string fileName in updateFileList)
                    {
                        fileVersion = fileName.Split('.');
                        if (fileVersion.Length == 4 &&
                            int.TryParse(fileVersion[0], out outVersion) &&
                            int.TryParse(fileVersion[1], out outVersion) &&
                            int.TryParse(fileVersion[2], out outVersion) &&
                            int.TryParse(fileVersion[3], out outVersion)) // 1.0.0.0 数字格式
                        {
                            if (string.IsNullOrWhiteSpace(latestFileName))
                            {
                                latestFileName = fileName;
                                continue;
                            }
                            else // 比较版本大小
                            {
                                latestVersion = latestFileName.Split('.');
                                for (int i = 0; i < fileVersion.Length; i++) // 逐个比较
                                {
                                    if (int.Parse(fileVersion[i]) > int.Parse(latestVersion[i]))
                                    {
                                        latestFileName = fileName;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    return latestFileName;
                }
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return string.Empty;
        }

        #region Enum

        /// <summary>
        /// 获取枚举值的详细文本信息
        /// </summary>
        /// <param name="e">Enum</param>
        /// <returns>文本信息</returns>
        public static string GetEnumDisplayDescription(object e)
        {
            if (e == null)
                return string.Empty;

            try
            {
                FieldInfo[] fields = e.GetType().GetFields(BindingFlags.Public | BindingFlags.Static); // 获取字段信息

                foreach (FieldInfo info in fields)
                {
                    if (!info.Name.Equals(e.ToString())) // 判断名称是否相等
                        continue;

                    DisplayAttribute displayAttribute = info.GetCustomAttributes(typeof(DisplayAttribute), true).Cast<DisplayAttribute>().FirstOrDefault<DisplayAttribute>(); // 获取 Display 属性
                    if (displayAttribute != null)
                    {
                        if (displayAttribute.ResourceType != null &&
                            !string.IsNullOrWhiteSpace(displayAttribute.Name))
                        {
                            ResourceManager resourceManager = new ResourceManager(displayAttribute.ResourceType);
                            if (resourceManager != null)
                                return resourceManager.GetString(displayAttribute.Name); // 得到文本信息
                        }
                        else if (!string.IsNullOrWhiteSpace(displayAttribute.Description))
                        {
                            return displayAttribute.Description;
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return e.ToString();
        }

        /// <summary>
        /// 获取所有枚举值
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <returns></returns>
        public static T[] GetEnumValues<T>()
        {
            try
            {
                Type type = typeof(T);

                if (!type.IsEnum)
                {
                    throw new InvalidOperationException("T 必须为枚举类型");
                }

                var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static).Where(fi => fi.IsLiteral);
                return fields.Select(fi => (T)fi.GetValue(type)).ToArray();
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return null;
            }
        }

        #endregion

        #region XML

        public static string GetXmlNodeAttValue(XElement node, string attrName)
        {
            return node.Attribute(attrName) == null ? "" : node.Attribute(attrName).Value;
        }

        public static int? GetXmlNodelIntValue(XElement node, string attrName)
        {
            if (node.Attribute(attrName) == null)
                return null;

            int r;
            if (int.TryParse(node.Attribute(attrName).Value, out r))
            {
                return r;
            }

            return null;
        }

        public static string GetXmlNodeValue(XElement node)
        {
            if (node == null)
                return string.Empty;

            return node.Value;
        }

        #endregion

        #region 类型转换

        public static bool ToBool(string value, bool defaultValue)
        {
            bool r;
            if (bool.TryParse(value, out r))
            {
                return r;
            }

            return defaultValue;
        }

        public static int ToInt(string value, int defaultValue)
        {
            int r;
            if (int.TryParse(value, out r))
            {
                return r;
            }

            return defaultValue;
        }

        public static double ToDouble(string value, double defaultValue)
        {
            double r;
            if (double.TryParse(value, out r))
            {
                return r;
            }

            return defaultValue;
        }

        #endregion

        #endregion
    }
}
